package com.gjy.service.es.service;

import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-08-04 15:27:19
 */
public class ElasticsearchAggregationService {

    private final RestHighLevelClient client;

    public ElasticsearchAggregationService(RestHighLevelClient client) {
        this.client = client;
    }

    /**
     * 执行多层嵌套桶聚合
     *
     * @param indexName     索引名称
     * @param fieldPathList 聚合字段路径列表（顺序决定聚合层级）
     * @return 嵌套结构的聚合结果
     */
    public Map<String, Object> executeNestedAggregation(String indexName, List<String> fieldPathList) {
        // 1. 构建聚合链
        AggregationBuilder rootAggregation = buildAggregationChain(fieldPathList);

        // 2. 创建搜索请求
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
                .size(0)  // 不需要返回原始文档
                .aggregation(rootAggregation);

        SearchRequest request = new SearchRequest(indexName)
                .source(sourceBuilder);

        try {
            // 3. 执行搜索
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            // 4. 解析嵌套聚合结果
            return parseAggregationResponse(response, fieldPathList);
        } catch (IOException e) {
            throw new ElasticsearchException("聚合查询执行失败: " + e.getMessage(), e);
        }
    }

    /**
     * 递归构建嵌套聚合链
     *
     * @param fields 字段路径列表
     * @return 根聚合Builder
     */
    private AggregationBuilder buildAggregationChain(List<String> fields) {
        if (fields.isEmpty()) throw new IllegalArgumentException("字段列表不能为空");

        // 创建最底层的聚合
        TermsAggregationBuilder currentAgg = AggregationBuilders
                .terms(fields.get(0) + "_agg")
                .field(fields.get(0))
                .size(10000);  // 确保返回所有桶

        // 递归添加子聚合
        for (int i = 1; i < fields.size(); i++) {
            TermsAggregationBuilder childAgg = AggregationBuilders
                    .terms(fields.get(i) + "_agg")
                    .field(fields.get(i))
                    .size(10000);
            currentAgg.subAggregation(childAgg);
            currentAgg = childAgg;
        }
        return currentAgg;
    }

    /**
     * 递归解析嵌套聚合结果
     *
     * @param response      搜索响应
     * @param fieldPathList 字段路径列表
     * @return 结构化聚合结果
     */
    private Map<String, Object> parseAggregationResponse(SearchResponse response, List<String> fieldPathList) {
        Map<String, Object> result = new HashMap<>();
        Aggregation rootAgg = response.getAggregations().get(fieldPathList.get(0) + "_agg");

        if (rootAgg instanceof Terms) {
            parseTermsAggregation((Terms) rootAgg, fieldPathList, 0, result);
        }
        return result;
    }

    /**
     * 递归解析Terms聚合
     *
     * @param terms 当前层级的聚合对象
     * @fieldPathList 字段路径列表
     * @currentLevel 当前处理层级
     * @resultNode 当前结果节点
     */
    private void parseTermsAggregation(Terms terms, List<String> fieldPathList, int currentLevel, Map<String, Object> resultNode) {
        // 1. 获取当前层所有桶
        List<? extends Terms.Bucket> buckets = terms.getBuckets();

        // 2. 遍历每个桶
        for (Terms.Bucket bucket : buckets) {
            String bucketKey = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();

            // 3. 构建当前桶的结果结构
            Map<String, Object> bucketData = new HashMap<>();
            bucketData.put("doc_count", docCount);

            // 4. 递归处理子聚合
            if (currentLevel < fieldPathList.size() - 1) {
                String nextAggName = fieldPathList.get(currentLevel + 1) + "_agg";
                Aggregation nextAgg = bucket.getAggregations().get(nextAggName);

                if (nextAgg instanceof Terms) {
                    parseTermsAggregation((Terms) nextAgg, fieldPathList, currentLevel + 1, bucketData);
                }
            }

            // 5. 将当前桶添加到结果树
            resultNode.put(bucketKey, bucketData);
        }
    }

}
